"""
增强的设备状态管理器
集成快速离线检测和ONVIF服务检查功能
"""

import asyncio
import time
from datetime import datetime, timedelta
from typing import Dict, List, Optional, Set, Tuple
from dataclasses import dataclass
from concurrent.futures import ThreadPoolExecutor, as_completed
from loguru import logger

from ..models.device import DeviceInfo, DeviceStatus, NetworkMetrics, DeviceStatusRecord
from ..utils.config import Config
from .network_monitor import NetworkMonitor
from .enhanced_device_monitor import EnhancedDeviceMonitor, QuickCheckResult, FailureTracker
from .onvif_service_checker import ONVIFServiceChecker, ONVIFServiceStatus


@dataclass
class DeviceHealthStatus:
    """设备健康状态"""
    device_id: str
    ip_address: str
    status: DeviceStatus
    last_online_time: datetime
    last_check_time: datetime
    consecutive_failures: int
    failure_reasons: List[str]
    network_metrics: Optional[NetworkMetrics] = None
    onvif_status: Optional[ONVIFServiceStatus] = None
    
    @property
    def offline_duration(self) -> Optional[timedelta]:
        """离线持续时间"""
        if self.status == DeviceStatus.ONLINE:
            return None
        return datetime.now() - self.last_online_time
    
    @property
    def is_critical(self) -> bool:
        """是否为关键状态（长时间离线或多次失败）"""
        if self.status == DeviceStatus.OFFLINE:
            offline_time = self.offline_duration
            if offline_time and offline_time.total_seconds() > 300:  # 5分钟
                return True
        return self.consecutive_failures >= 5


class DeviceStatusManager:
    """设备状态管理器"""
    
    def __init__(self, config: Config):
        self.config = config
        self.device_statuses: Dict[str, DeviceHealthStatus] = {}
        
        # 初始化监控组件
        self.network_monitor = NetworkMonitor(
            ping_timeout=config.monitoring.ping.timeout,
            ping_count=config.monitoring.ping.packet_count
        )
        self.enhanced_monitor = EnhancedDeviceMonitor(config)
        self.onvif_checker = ONVIFServiceChecker(timeout=3.0)
        
        # 线程池用于并发监控
        self.executor = ThreadPoolExecutor(max_workers=20)
        
        # 监控配置
        self.quick_check_enabled = True
        self.quick_check_threshold = 2  # 连续2次常规检测失败后启用快速检测
        self.offline_confirmation_time = 5.0  # 5秒内确认离线
        
        logger.info("设备状态管理器初始化完成")
    
    def get_device_status(self, device_id: str) -> Optional[DeviceHealthStatus]:
        """获取设备状态"""
        return self.device_statuses.get(device_id)
    
    def update_device_status(self, device: DeviceInfo, status: DeviceStatus, 
                           failure_reason: str = "", network_metrics: NetworkMetrics = None,
                           onvif_status: ONVIFServiceStatus = None):
        """
        更新设备状态
        
        Args:
            device: 设备信息
            status: 新状态
            failure_reason: 失败原因
            network_metrics: 网络指标
            onvif_status: ONVIF服务状态
        """
        device_id = device.device_id
        now = datetime.now()
        
        if device_id not in self.device_statuses:
            # 新设备
            self.device_statuses[device_id] = DeviceHealthStatus(
                device_id=device_id,
                ip_address=device.ip_address,
                status=status,
                last_online_time=now if status == DeviceStatus.ONLINE else now,
                last_check_time=now,
                consecutive_failures=0 if status == DeviceStatus.ONLINE else 1,
                failure_reasons=[] if status == DeviceStatus.ONLINE else [failure_reason],
                network_metrics=network_metrics,
                onvif_status=onvif_status
            )
        else:
            # 更新现有设备
            health_status = self.device_statuses[device_id]
            old_status = health_status.status
            
            health_status.status = status
            health_status.last_check_time = now
            health_status.network_metrics = network_metrics
            health_status.onvif_status = onvif_status
            
            if status == DeviceStatus.ONLINE:
                # 设备恢复在线
                if old_status != DeviceStatus.ONLINE:
                    logger.info(f"设备恢复在线: {device.ip_address} ({device_id})")
                
                health_status.last_online_time = now
                health_status.consecutive_failures = 0
                health_status.failure_reasons.clear()
                
                # 清除增强监控器中的失败跟踪
                self.enhanced_monitor.clear_failure_tracker(device_id)
            else:
                # 设备离线或异常
                if old_status == DeviceStatus.ONLINE:
                    logger.warning(f"设备状态变更: {device.ip_address} ({device_id}) - {old_status} -> {status}")
                
                health_status.consecutive_failures += 1
                if failure_reason:
                    health_status.failure_reasons.append(f"{now.strftime('%H:%M:%S')}: {failure_reason}")
                    
                    # 只保留最近10条失败记录
                    if len(health_status.failure_reasons) > 10:
                        health_status.failure_reasons = health_status.failure_reasons[-10:]
    
    def perform_standard_check(self, device: DeviceInfo) -> Tuple[DeviceStatus, str, Optional[NetworkMetrics], Optional[ONVIFServiceStatus]]:
        """
        执行标准设备检查
        
        Args:
            device: 设备信息
            
        Returns:
            Tuple[DeviceStatus, str, Optional[NetworkMetrics], Optional[ONVIFServiceStatus]]: 
            (状态, 失败原因, 网络指标, ONVIF状态)
        """
        logger.debug(f"执行标准检查: {device.ip_address}")
        
        # 网络检测
        network_metrics = self.network_monitor.ping_device(device.ip_address)
        
        # ONVIF服务检测
        onvif_status = self.onvif_checker.check_onvif_service(device.ip_address, device.port)
        
        # 判断设备状态
        if network_metrics.packet_loss_rate >= 100:
            return DeviceStatus.OFFLINE, "网络不可达", network_metrics, onvif_status
        
        if not onvif_status.is_available:
            if network_metrics.packet_loss_rate > 0:
                return DeviceStatus.NETWORK_ISSUE, f"网络不稳定，丢包率: {network_metrics.packet_loss_rate:.1f}%", network_metrics, onvif_status
            else:
                return DeviceStatus.SERVICE_ISSUE, f"ONVIF服务不可用: {onvif_status.error_message}", network_metrics, onvif_status
        
        # 检查网络质量
        if network_metrics.packet_loss_rate > 5:
            return DeviceStatus.NETWORK_ISSUE, f"网络质量差，丢包率: {network_metrics.packet_loss_rate:.1f}%", network_metrics, onvif_status
        
        if network_metrics.avg_latency > 200:
            return DeviceStatus.NETWORK_ISSUE, f"网络延迟过高: {network_metrics.avg_latency:.1f}ms", network_metrics, onvif_status
        
        return DeviceStatus.ONLINE, "", network_metrics, onvif_status
    
    def perform_quick_check(self, device: DeviceInfo) -> Tuple[DeviceStatus, str]:
        """
        执行快速检查（用于快速确认离线）
        
        Args:
            device: 设备信息
            
        Returns:
            Tuple[DeviceStatus, str]: (状态, 失败原因)
        """
        logger.info(f"执行快速离线检查: {device.ip_address}")
        
        is_offline, failure_reason = self.enhanced_monitor.rapid_offline_detection(device)
        
        if is_offline:
            return DeviceStatus.OFFLINE, failure_reason
        else:
            return DeviceStatus.ONLINE, ""
    
    def check_device(self, device: DeviceInfo, force_quick_check: bool = False) -> DeviceHealthStatus:
        """
        检查单个设备状态
        
        Args:
            device: 设备信息
            force_quick_check: 是否强制执行快速检查
            
        Returns:
            DeviceHealthStatus: 设备健康状态
        """
        device_id = device.device_id
        current_status = self.get_device_status(device_id)
        
        # 决定使用哪种检查方式
        use_quick_check = force_quick_check
        
        if not use_quick_check and current_status:
            # 如果设备连续失败次数达到阈值，启用快速检查
            if current_status.consecutive_failures >= self.quick_check_threshold:
                use_quick_check = True
                logger.info(f"设备连续失败{current_status.consecutive_failures}次，启用快速检查: {device.ip_address}")
        
        try:
            if use_quick_check and self.quick_check_enabled:
                # 快速检查
                status, failure_reason = self.perform_quick_check(device)
                self.update_device_status(device, status, failure_reason)
            else:
                # 标准检查
                status, failure_reason, network_metrics, onvif_status = self.perform_standard_check(device)
                self.update_device_status(device, status, failure_reason, network_metrics, onvif_status)
            
        except Exception as e:
            logger.error(f"设备检查异常: {device.ip_address} - {e}")
            self.update_device_status(device, DeviceStatus.UNKNOWN, f"检查异常: {str(e)}")
        
        return self.device_statuses[device_id]
    
    def check_devices_batch(self, devices: List[DeviceInfo], max_workers: int = 10) -> Dict[str, DeviceHealthStatus]:
        """
        批量检查设备状态
        
        Args:
            devices: 设备列表
            max_workers: 最大并发数
            
        Returns:
            Dict[str, DeviceHealthStatus]: 设备状态字典
        """
        logger.info(f"开始批量检查 {len(devices)} 个设备")
        
        results = {}
        
        with ThreadPoolExecutor(max_workers=max_workers) as executor:
            # 提交检查任务
            future_to_device = {
                executor.submit(self.check_device, device): device 
                for device in devices
            }
            
            # 收集结果
            for future in as_completed(future_to_device):
                device = future_to_device[future]
                try:
                    health_status = future.result()
                    results[device.device_id] = health_status
                except Exception as e:
                    logger.error(f"设备检查任务异常: {device.ip_address} - {e}")
                    # 创建错误状态
                    self.update_device_status(device, DeviceStatus.UNKNOWN, f"任务异常: {str(e)}")
                    results[device.device_id] = self.device_statuses[device.device_id]
        
        logger.info(f"批量检查完成，结果: {len(results)} 个设备")
        return results
    
    def get_offline_devices(self) -> List[DeviceHealthStatus]:
        """获取离线设备列表"""
        return [status for status in self.device_statuses.values() 
                if status.status == DeviceStatus.OFFLINE]
    
    def get_critical_devices(self) -> List[DeviceHealthStatus]:
        """获取关键状态设备列表"""
        return [status for status in self.device_statuses.values() if status.is_critical]
    
    def get_monitoring_summary(self) -> Dict:
        """获取监控摘要"""
        total = len(self.device_statuses)
        online = sum(1 for s in self.device_statuses.values() if s.status == DeviceStatus.ONLINE)
        offline = sum(1 for s in self.device_statuses.values() if s.status == DeviceStatus.OFFLINE)
        network_issue = sum(1 for s in self.device_statuses.values() if s.status == DeviceStatus.NETWORK_ISSUE)
        service_issue = sum(1 for s in self.device_statuses.values() if s.status == DeviceStatus.SERVICE_ISSUE)
        unknown = sum(1 for s in self.device_statuses.values() if s.status == DeviceStatus.UNKNOWN)
        critical = len(self.get_critical_devices())
        
        return {
            'total_devices': total,
            'online_devices': online,
            'offline_devices': offline,
            'network_issue_devices': network_issue,
            'service_issue_devices': service_issue,
            'unknown_devices': unknown,
            'critical_devices': critical,
            'online_rate': online / total if total > 0 else 0,
            'quick_check_enabled': self.quick_check_enabled,
            'enhanced_monitor_stats': self.enhanced_monitor.get_monitoring_stats()
        }
    
    def cleanup_old_records(self, retention_hours: int = 24):
        """清理旧的设备记录"""
        cutoff_time = datetime.now() - timedelta(hours=retention_hours)
        
        devices_to_remove = []
        for device_id, status in self.device_statuses.items():
            if status.last_check_time < cutoff_time:
                devices_to_remove.append(device_id)
        
        for device_id in devices_to_remove:
            del self.device_statuses[device_id]
            self.enhanced_monitor.clear_failure_tracker(device_id)
        
        if devices_to_remove:
            logger.info(f"清理了 {len(devices_to_remove)} 个旧设备记录")
    
    def __del__(self):
        """清理资源"""
        if hasattr(self, 'executor'):
            self.executor.shutdown(wait=False)
